//
//  Render.m
//  whfDemo
//
//  Created by 王洪飞 on 2024/2/20.
//

#import "Render.h"
#import <OpenGLES/ES2/gl.h>
#import <OpenGLES/ES2/glext.h>
#import "GLProgram.h"

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"


@interface Render ()
{
    EAGLContext *mContext;

    CAEAGLLayer *mEagllayer;
    
    GLuint frameBuffer;
    GLuint renderBuffer;
    
    GLuint texture;
    
    GLProgram *programObj;
}

-(void)setupContext;
-(void)setupEagllayer;
-(void)setupRenderbuffer;
-(void)setupFramebuffer;
-(void)draw;

@end

@implementation Render

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self setupContext];
        [self setupEagllayer];
        [self setupProgram];
//        [self loadTexture];
    }
    return self;
}

+(Class)layerClass{
    return [CAEAGLLayer class];
}

-(void)setupContext{
    mContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
    [EAGLContext setCurrentContext:mContext];
}

-(void)setupEagllayer{
    mEagllayer = (CAEAGLLayer *)self.layer;
    mEagllayer.opaque = NO;
    mEagllayer.drawableProperties = @{
        kEAGLDrawablePropertyColorFormat:kEAGLColorFormatRGBA8,
        kEAGLDrawablePropertyRetainedBacking:@(NO)
    };
}

- (void)setupRenderbuffer{
    renderBuffer = 0;
    glGenRenderbuffers(1, &renderBuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
    [mContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:mEagllayer];
}

-(void)setupFramebuffer{
    frameBuffer = 0;
    glGenFramebuffers(1, &frameBuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderBuffer);
}

- (void)layoutSubviews{
    [self destory];
    [self setupRenderbuffer];
    [self setupFramebuffer];
    [self loadTexture];
    [self draw];
}

-(void)draw{
    glClearColor(0, 100, 150, 10);
    glClear(GL_COLOR_BUFFER_BIT);
    glViewport(0, 0, self.frame.size.width, self.frame.size.height);
    
    GLfloat vertices[20] = {
        0.5,0.5,0.0,            1.0, 0.0,
        -0.5,0.5,0.0,            0.0, 0.0,
        0.5,-0.5,0.0,            1.0, 1.0,
        -0.5,-0.5,0.0,           0.0, 1.0,
    };
    
    GLuint indices[6] = {
        0,1,2,1,2,3
    };
    
    glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
    
    
    GLuint vaoId, eleId;
    glGenBuffers(1, &vaoId);
    glBindBuffer(GL_ARRAY_BUFFER, vaoId);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    
    glGenBuffers(1, &eleId);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eleId);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
    
    GLuint vpos = [programObj attributeIndex:@"vPos"]; //glGetAttribLocation(program, "vPos");
    glVertexAttribPointer(vpos, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, 0);
    glEnableVertexAttribArray(vpos);
    
    GLuint vCoord = [programObj attributeIndex:@"vCoord"];
    glVertexAttribPointer(vCoord, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLfloat *)NULL + 3);
    glEnableVertexAttribArray(vCoord);
    
   
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, NULL);
    [mContext presentRenderbuffer:GL_RENDERBUFFER];
    
    GLubyte *outputBytes = (GLubyte *)malloc(2*2 * 4);
    glReadPixels(0, 0, 2, 2, GL_RGBA, GL_UNSIGNED_BYTE, outputBytes);
    
    int bytesPerRow = 8;
    for (unsigned int yIndex = 0; yIndex < 2; yIndex++)
    {
        for (unsigned int xIndex = 0; xIndex < 2; xIndex++)
        {
            NSLog(@"Byte at (%d, %d): %d, %d, %d, %d", xIndex, yIndex, outputBytes[yIndex * bytesPerRow + xIndex * 4], outputBytes[yIndex * bytesPerRow + xIndex * 4 + 1], outputBytes[yIndex * bytesPerRow + xIndex * 4 + 2], outputBytes[yIndex * bytesPerRow + xIndex * 4 + 3]);
        }
    }
    NSLog(@"\n\n\n");
}

-(void)destory{
    glDeleteRenderbuffers(1, &renderBuffer);
    glDeleteFramebuffers(1, &frameBuffer);
    renderBuffer = 0;
    frameBuffer = 0;
}

-(void)setupProgram{
    NSString *vShaderStr = @""
    "attribute vec3 vPos;\n"
    "attribute vec2 vCoord;\n"
    "varying vec2 coord;\n"
    "void main(){gl_Position = vec4(vPos,1.0);"
    "coord = vCoord;\n}";
    NSString *fShaderStr = @""
    "precision mediump float;"
    "varying vec2 coord;\n"
    "uniform sampler2D s_texture;\n"
    "void main(){gl_FragColor = texture2D(s_texture,coord);}";
    programObj = [[GLProgram alloc] initWithVertexShaderString:vShaderStr fragmentShaderString:fShaderStr];
    if([programObj link]){
        [programObj use];
        [programObj addAttribute:@"vPos"];
    }
}

-(void)loadTexture{
    GLubyte pixels[] = {
        255,0,0,255,
        0,255,0,255,
        0,0,255,255,
        100,100,0,255,
    };
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);


  
    
    
    //将纹理绑定到FBO
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
    
    GLenum err = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    if (err != GL_FRAMEBUFFER_COMPLETE) {
        NSLog(@"frame buffer error %u %x", err, err);
    }else{
        NSLog(@"frame buffer success");
    }
    // 不加，则glReadPixels读取不到数据
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
}


@end

#pragma clang diagnostic pop

